#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
全局异常处理模块
用于捕获和记录系统中的异常
"""

import logging
import traceback
import json
import sys
import os
from datetime import datetime

from django.http import JsonResponse
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings
from common import errors

# 创建错误日志记录器
error_logger = logging.getLogger('error')

class GlobalExceptionMiddleware(MiddlewareMixin):
    """
    全局异常处理中间件，捕获并记录所有未处理的异常
    """
    
    def process_exception(self, request, exception):
        """处理视图函数中抛出的异常"""
        # 获取请求信息
        method = request.method
        path = request.path
        ip = self._get_client_ip(request)
        user = getattr(request, 'user', None)
        user_id = user.id if hasattr(user, 'id') and user.is_authenticated else 'anonymous'

        # 获取异常信息
        exc_type, exc_value, exc_traceback = sys.exc_info()
        stack_trace = traceback.format_exception(exc_type, exc_value, exc_traceback)
        exception_class = exception.__class__.__name__
        
        # 构建错误日志
        error_data = {
            'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'request_method': method,
            'request_path': path,
            'client_ip': ip,
            'user_id': user_id,
            'exception_type': exception_class,
            'exception_message': str(exception),
            'stack_trace': ''.join(stack_trace),
            'request_data': self._get_request_data(request)
        }
        
        # 记录错误日志
        error_logger.error(
            f"[Unhandled Exception] {exception_class}: {str(exception)} - "
            f"{method} {path} - User: {user_id} - IP: {ip}", 
            extra={'error_data': error_data}
        )
        
        # 如果是已知的业务逻辑错误，则使用其响应
        if isinstance(exception, errors.LogicError):
            return JsonResponse({
                'code': exception.code,
                'message': exception.message
            }, status=200)
        
        # 如果是调试模式，返回详细错误信息
        if settings.DEBUG:
            return JsonResponse({
                'code': 500,
                'message': f'服务器错误: {str(exception)}',
                'exception_type': exception_class,
                'stack_trace': stack_trace,
            }, status=500)
        
        # 生产环境返回简洁的错误信息
        return JsonResponse({
            'code': 500,
            'message': '服务器内部错误，请稍后再试'
        }, status=500)
    
    def _get_client_ip(self, request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
        else:
            ip = request.META.get('REMOTE_ADDR', 'unknown')
        return ip
    
    def _get_request_data(self, request):
        """安全地获取请求数据"""
        data = {}
        
        # 尝试获取GET参数
        try:
            if request.GET:
                data['GET'] = dict(request.GET)
        except Exception:
            data['GET'] = 'Error extracting GET data'
        
        # 尝试获取POST参数
        try:
            if request.POST:
                # 过滤敏感字段
                post_data = dict(request.POST)
                for key in ['password', 'token', 'secret']:
                    if key in post_data:
                        post_data[key] = '*****'
                data['POST'] = post_data
        except Exception:
            data['POST'] = 'Error extracting POST data'
        
        # 尝试获取JSON数据
        try:
            if 'application/json' in request.content_type:
                json_data = json.loads(request.body)
                # 过滤敏感字段
                if isinstance(json_data, dict):
                    for key in ['password', 'token', 'secret']:
                        if key in json_data:
                            json_data[key] = '*****'
                data['JSON'] = json_data
        except Exception:
            pass
        
        return data


def log_error(exception, context=None):
    """
    记录异常到错误日志
    
    参数:
        exception: 异常对象或错误消息
        context: 上下文信息，如请求数据、用户信息等
    """
    error_message = str(exception)
    error_class = exception.__class__.__name__ if isinstance(exception, Exception) else 'Error'
    
    # 获取调用栈信息
    stack_trace = traceback.format_exc() if isinstance(exception, Exception) else 'No traceback'
    
    # 构建错误日志
    error_data = {
        'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'error_class': error_class,
        'error_message': error_message,
        'stack_trace': stack_trace,
        'context': context or {}
    }
    
    # 记录错误日志
    error_logger.error(f"[Error] {error_class}: {error_message}", extra={'error_data': error_data})


def exception_handler(func):
    """
    异常处理装饰器，用于捕获函数中的异常并记录日志
    
    使用方法:
        @exception_handler
        def some_function():
            # 可能抛出异常的代码
    """
    def wrapped_function(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            # 获取函数信息和调用参数
            func_name = func.__name__
            module_name = func.__module__
            
            # 过滤和截断参数，避免记录敏感信息或过大的数据
            safe_args = []
            for arg in args:
                if isinstance(arg, (str, int, float, bool, type(None))):
                    safe_args.append(arg)
                else:
                    safe_args.append(f"<{type(arg).__name__}>")
            
            safe_kwargs = {}
            for key, value in kwargs.items():
                if key.lower() in ['password', 'token', 'secret']:
                    safe_kwargs[key] = '*****'
                elif isinstance(value, (str, int, float, bool, type(None))):
                    safe_kwargs[key] = value
                else:
                    safe_kwargs[key] = f"<{type(value).__name__}>"
            
            # 记录错误日志
            log_error(e, {
                'function': f"{module_name}.{func_name}",
                'args': safe_args,
                'kwargs': safe_kwargs
            })
            
            # 重新抛出异常
            raise
    
    return wrapped_function 